/*
 * Android Runner is a multiplayer GPS game fully written by Xurxo Mendez Perez
 * 
 * Copyright (C) 2009 Xurxo Mendez Perez
 *   
 * This file is part of Android Runner.
 * 
 * Android Runner is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Android Runner is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Android Runner.  If not, see <http://www.gnu.org/licenses/>.
 */

package es.sonxurxo.gpsgame.client.model.util.http;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

import es.sonxurxo.gpsgame.client.model.service.to.FinishedGame;
import es.sonxurxo.gpsgame.client.model.service.to.Game;
import es.sonxurxo.gpsgame.client.model.service.to.GameCTO;
import es.sonxurxo.gpsgame.client.model.service.to.Player;
import es.sonxurxo.gpsgame.client.model.service.to.PublicPlayerProfileTO;
import es.sonxurxo.gpsgame.client.model.service.to.response.AnswerQuestionResponseTO;
import es.sonxurxo.gpsgame.client.model.service.to.response.GenericGameResponseTO;
import es.sonxurxo.gpsgame.client.model.service.to.response.GetItemResponseTO;
import es.sonxurxo.gpsgame.client.model.service.to.response.StartOrContinueGameResponseTO;
import es.sonxurxo.gpsgame.client.model.util.xml.XMLToBussinessConversor;
import es.sonxurxo.gpsgame.client.util.exception.ServerException;

/**
 * 
 * @author "Xurxo Mendez Perez"
 *
 */
public class HttpHelper {

	private final String SERVER_HOST_IP = "ingame.androidrunner.com";
	private final String SERVER_PORT = "80";
	private final String GAME_URL = "ingame";
	private final String FULL_ADDRESS = "http://" + SERVER_HOST_IP + ":" + 
		SERVER_PORT + "/" + GAME_URL + "/";
	
	private final String LOGIN_URL = "login";
	private final String REGISTER_URL = "register";
	private final String LOGOUT_URL = "logout";
	private final String UPDATE_PERSONAL_INFO_URL = "updatePersonalInfo";
	private final String GET_HISTORY_URL = "getHistoryOfGames";
	private final String CHANGE_PASSWORD_URL = "changePassword";
	private final String GET_PUBLIC_PLAYER_PROFILE_URL = "getPublicPlayerProfile";
	
	private final String FIND_CITIES_WITH_GAMES_URL = "findCitiesWithGames";
	private final String FIND_GAME_BY_ID_URL = "findGameById";
	private final String FIND_GAMES_BY_CITY_URL = "findGamesByCity";
	private final String FIND_GAMES_BY_LOCATION_URL = "findGamesByLocation";
	private final String JOIN_GAME_URL = "joinGame";
	private final String ABANDON_GAME_URL = "abandonGame";
	private final String START_OR_CONTINUEGAME_URL = "startOrContinueGame";
	
	private final String UPDATE_LOCATION_URL = "updateLocation";
	private final String GET_ITEM_URL = "getItem";
	private final String SEND_MESSAGE_URL = "sendMessage";
	private final String ANSWER_QUESTION_URL = "answerQuestion";
	
	private final String LOGIN_PARAMETER = "login";
	private final String EMAIL_PARAMETER = "email";
	private final String SHOW_PERSONAL_INFO_PARAMETER = "showPersonalInfo";
	private final String PHONE_PARAMETER = "phone";
	private final String CLEAR_PASSWORD_PARAMETER = "clearPassword";
	private final String OLD_CLEAR_PASSWORD_PARAMETER = "oldClearPassword";
	private final String NEW_CLEAR_PASSWORD_PARAMETER = "newClearPassword";
	private final String NAME_PARAMETER = "name";
	private final String SURNAME_PARAMETER = "surname";
	private final String COUNTRY_PARAMETER = "country";
	private final String IMAGE_ID_PARAMETER = "imageId";
	private final String GAME_ID_PARAMETER = "gameId";
	private final String CITY_PARAMETER = "city";
	private final String LATITUDE_PARAMETER = "latitude";
	private final String LONGITUDE_PARAMETER = "longitude";
	private final String ACCURATE_PARAMETER = "accurate";
	private final String ITEM_ID_PARAMETER = "itemId";
	private final String RECEIVER_LOGIN_PARAMETER = "receiverLogin";
	private final String BODY_PARAMETER = "body";
	private final String QUESTION_ID_PARAMETER = "questionId";
	private final String START_INDEX_PARAMETER = "startIndex";
	private final String COUNT_PARAMETER = "count";
	
	private static HttpClient client = new DefaultHttpClient();
	private HttpUriRequest request;
	private HttpResponse response;
	private static HttpHelper instance;

	static {
		instance = new HttpHelper();
	}

	public static HttpHelper getInstance() {
		return instance;
	}
	
	public Player loginPlayer(String login, String clearPassword) 
	throws Exception {

		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
		String encodedPassword = URLEncoder.encode(clearPassword.replace("%2B", "+"), "UTF-8");
        request = new HttpGet(FULL_ADDRESS + 
        		LOGIN_URL + "?" + 
        		LOGIN_PARAMETER + "=" + encodedLogin + "&" + 
        		CLEAR_PASSWORD_PARAMETER + "=" + encodedPassword);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toPlayer(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
        			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public boolean registerPlayer(String login, String clearPassword, String email,
			boolean showPersonalInfo, String phone, String name, String surname, String country,
			int imageId) 
	throws Exception {

		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
		String encodedPassword = URLEncoder.encode(clearPassword.replace("%2B", "+"), "UTF-8");
		String encodedEmail = URLEncoder.encode(email.replace("%2B", "+"), "UTF-8");
		String encodedPhone = URLEncoder.encode(phone, "UTF-8");
		String encodedName = URLEncoder.encode(name.replace("%2B", "+"), "UTF-8");
		String encodedSurname = URLEncoder.encode(surname.replace("%2B", "+"), "UTF-8");
		String encodedCountry = URLEncoder.encode(country.replace("%2B", "+"), "UTF-8");

		request = new HttpPost(FULL_ADDRESS + 
				REGISTER_URL + "?" + 
	       		LOGIN_PARAMETER + "=" + encodedLogin + "&" + 
	       		CLEAR_PASSWORD_PARAMETER + "=" + encodedPassword + "&" + 
	       		EMAIL_PARAMETER + "=" + encodedEmail + "&" + 
	       		SHOW_PERSONAL_INFO_PARAMETER + "=" + String.valueOf(showPersonalInfo) + "&" + 
	       		PHONE_PARAMETER + "=" + encodedPhone + "&" + 
	       		NAME_PARAMETER + "=" + encodedName + "&" + 
	       		SURNAME_PARAMETER + "=" + encodedSurname + "&" + 
	       		COUNTRY_PARAMETER + "=" + encodedCountry + "&" + 
	       		IMAGE_ID_PARAMETER + "=" + imageId);

//		BasicHttpParams params = new BasicHttpParams();
//		request.addHeader(LOGIN_PARAMETER, encodedLogin);
//		request.addHeader(CLEAR_PASSWORD_PARAMETER, encodedPassword);
//		request.addHeader(EMAIL_PARAMETER, encodedEmail);
//		request.addHeader(SHOW_PERSONAL_INFO_PARAMETER, String.valueOf(showPersonalInfo));
//		request.addHeader(PHONE_PARAMETER, encodedPhone);
//		request.addHeader(NAME_PARAMETER, encodedName);
//		request.addHeader(SURNAME_PARAMETER, encodedSurname);
//		request.addHeader(COUNTRY_PARAMETER, encodedCountry);
//		request.addHeader(IMAGE_ID_PARAMETER, String.valueOf(imageId));
//		request.setParams(params);
        try {
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();
        	return XMLToBussinessConversor.toBooleanOrExceptionRegister(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public boolean updatePlayer(String email, boolean showEmail, String phone, String name, 
			String surname, String country, int imageId) 
	throws Exception {
		
		String encodedEmail = URLEncoder.encode(email.replace("%2B", "+"), "UTF-8");
		String encodedPhone = URLEncoder.encode(phone, "UTF-8");
		String encodedName = URLEncoder.encode(name.replace("%2B", "+"), "UTF-8");
		String encodedSurname = URLEncoder.encode(surname.replace("%2B", "+"), "UTF-8");
		String encodedCountry = URLEncoder.encode(country.replace("%2B", "+"), "UTF-8");

		request = new HttpPost(FULL_ADDRESS + 
				UPDATE_PERSONAL_INFO_URL + "?" +
        		EMAIL_PARAMETER + "=" + encodedEmail + "&" + 
        		SHOW_PERSONAL_INFO_PARAMETER + "=" + String.valueOf(showEmail) + "&" + 
        		PHONE_PARAMETER + "=" + encodedPhone + "&" + 
        		NAME_PARAMETER + "=" + encodedName + "&" + 
        		SURNAME_PARAMETER + "=" + encodedSurname + "&" + 
        		COUNTRY_PARAMETER + "=" + encodedCountry + "&" + 
        		IMAGE_ID_PARAMETER + "=" + imageId);

        try {
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();
        	return XMLToBussinessConversor.toBooleanOrExceptionUpdate(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public PublicPlayerProfileTO getPublicPlayerProfile(String login) 
	throws Exception {
		
		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
        request = new HttpGet(FULL_ADDRESS + 
        		GET_PUBLIC_PLAYER_PROFILE_URL + "?" + 
        		LOGIN_PARAMETER + "=" + encodedLogin);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toPublicPlayer(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public void logoutPlayer(String login) 
	throws Exception {
		
		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
        request = new HttpGet(FULL_ADDRESS + 
        		LOGOUT_URL + "?" + 
        		LOGIN_PARAMETER + "=" + encodedLogin);
        
        try {
        	response = client.execute(request);
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public List<FinishedGame> getHistory(String login) throws Exception {
		
		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
        request = new HttpGet(FULL_ADDRESS + 
        		GET_HISTORY_URL + "?" + 
        		LOGIN_PARAMETER + "=" + encodedLogin);
        
        try {
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();
        	return XMLToBussinessConversor.toFinishedGameList(
        			entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public List<String> findCitiesWithGames() throws Exception {
		
		request = new HttpGet(FULL_ADDRESS + 
				FIND_CITIES_WITH_GAMES_URL);
		
		try {
			response = client.execute(request);
			HttpEntity entity = response.getEntity();
			
			return XMLToBussinessConversor.toCityList(entity);
		} catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public Game findGame(String gameId) 
	throws Exception {
		
		request = new HttpGet(FULL_ADDRESS + 
				FIND_GAME_BY_ID_URL + "?" + 
				GAME_ID_PARAMETER + "=" + gameId);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toGame(entity);

        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public GameCTO findGamesByCity(String city, int startIndex, int count) 
	throws Exception {
		String encodedCity = URLEncoder.encode(city.replace("%2B", "+"), "UTF-8");
		request = new HttpGet(FULL_ADDRESS + 
				FIND_GAMES_BY_CITY_URL + "?" + 
        		CITY_PARAMETER +  "=" + encodedCity + "&" + 
        		START_INDEX_PARAMETER +  "=" + startIndex + "&" + 
        		COUNT_PARAMETER +  "=" + count);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	GameCTO gameCTO = XMLToBussinessConversor.toGameList(entity);
        	return gameCTO;
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public GameCTO findGamesByLocation(int latitude, int longitude, 
			int accurate, int startIndex, int count) 
	throws Exception {
		
		String encodedLatitude = URLEncoder.encode(
				String.valueOf(latitude).replace("%2B", "+"), "UTF-8");
		String encodedLongitude = URLEncoder.encode(
				String.valueOf(longitude).replace("%2B", "+"), "UTF-8");
		String encodedAccurate= URLEncoder.encode(
				String.valueOf(accurate).replace("%2B", "+"), "UTF-8");
		request = new HttpGet(FULL_ADDRESS + 
				FIND_GAMES_BY_LOCATION_URL + "?" + 
        		LATITUDE_PARAMETER + "=" + encodedLatitude + "&" + 
        		LONGITUDE_PARAMETER + "=" + encodedLongitude + "&" + 
        		ACCURATE_PARAMETER + "=" + encodedAccurate + "&" + 
        		START_INDEX_PARAMETER +  "=" + startIndex + "&" + 
        		COUNT_PARAMETER +  "=" + count);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	GameCTO gameCTO = XMLToBussinessConversor.toGameList(entity);
        	return gameCTO;
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public boolean joinGame(long gameId) 
	throws Exception {
		
		String encodedGameId = URLEncoder.encode(
				String.valueOf(gameId).replace("%2B", "+"), "UTF-8");
		
		request = new HttpPost(FULL_ADDRESS + 
				JOIN_GAME_URL + "?" + 
        		GAME_ID_PARAMETER + "=" + encodedGameId);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toBooleanOrExceptionJoin(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}

	public boolean abandonGame(long gameId) 
	throws Exception {
		
		String encodedGameId = URLEncoder.encode(
				String.valueOf(gameId).replace("%2B", "+"), "UTF-8");
		
		request = new HttpPost(FULL_ADDRESS + 
				ABANDON_GAME_URL + "?" + 
        		GAME_ID_PARAMETER + "=" + encodedGameId);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toBooleanOrExceptionRemove(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public boolean changePassword(String oldPassword, String newPassword) 
	throws Exception {
		String encodedOldPassword = 
			URLEncoder.encode(oldPassword.replace("%2B", "+"), "UTF-8");	
		String encodedNewPassword = 
			URLEncoder.encode(newPassword.replace("%2B", "+"), "UTF-8");
		
		request = new HttpPost(FULL_ADDRESS + 
				CHANGE_PASSWORD_URL + "?" + 
        		OLD_CLEAR_PASSWORD_PARAMETER + "=" + encodedOldPassword + "&" + 
        		NEW_CLEAR_PASSWORD_PARAMETER + "=" + encodedNewPassword);
		
		try {        	
			
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	XMLToBussinessConversor.toBooleanOrExceptionChangePassword(entity);
        	return true;
		} catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
		
	}
	
	public StartOrContinueGameResponseTO startOrContinueGame(String login) 
	throws Exception {
		String encodedLogin = URLEncoder.encode(login.replace("%2B", "+"), "UTF-8");
		request = new HttpGet(FULL_ADDRESS + 
				START_OR_CONTINUEGAME_URL + "?" + 
				LOGIN_PARAMETER + "=" + encodedLogin);

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toStartOrContinueGameResponseTO(entity);

        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public GenericGameResponseTO updateLocation(int latitude, int longitude) 
	throws Exception {
		
		request = new HttpPost(FULL_ADDRESS + 
				UPDATE_LOCATION_URL + "?" + 
        		LATITUDE_PARAMETER + "=" + String.valueOf(latitude) + "&" +  
        		LONGITUDE_PARAMETER + "=" + String.valueOf(longitude));

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toGenericGameResponseTO(entity);

        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public GetItemResponseTO getItem(int latitude, int longitude, long itemId) 
	throws Exception {
		
		request = new HttpPost(FULL_ADDRESS + 
				GET_ITEM_URL + "?" + 
        		LATITUDE_PARAMETER + "=" + String.valueOf(latitude) + "&" +  
        		LONGITUDE_PARAMETER + "=" + String.valueOf(longitude) + "&" +
        		ITEM_ID_PARAMETER + "=" + String.valueOf(itemId));

        try {       	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toGetItemResponseTO(entity);

        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public boolean sendMessage(String receiverLogin, String body) 
	throws Exception {

		String encodedBody = 
			URLEncoder.encode(body.replace("%2B", "+"), "UTF-8");

		if (receiverLogin != null) {
			String encodedReceiverLogin = 
				URLEncoder.encode(receiverLogin.replace("%2B", "+"), "UTF-8");	

			request = new HttpPost(FULL_ADDRESS + 
	        		SEND_MESSAGE_URL + "?" + 
	        		RECEIVER_LOGIN_PARAMETER + "=" + encodedReceiverLogin + "&" +  
	        		BODY_PARAMETER + "=" + encodedBody);
		}
		else {
			request = new HttpGet(FULL_ADDRESS + 
	        		SEND_MESSAGE_URL + "?" + 
	        		BODY_PARAMETER + "=" + encodedBody);
		}

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toBooleanOrExceptionSend(entity);
        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
	
	public AnswerQuestionResponseTO answerQuestion(long questionId, int latitude, int longitude) 
	throws Exception {
		
		request = new HttpPost(FULL_ADDRESS + 
				ANSWER_QUESTION_URL + "?" + 
        		LATITUDE_PARAMETER + "=" + String.valueOf(latitude) + "&" +  
        		LONGITUDE_PARAMETER + "=" + String.valueOf(longitude) + "&" +
        		QUESTION_ID_PARAMETER + "=" + String.valueOf(questionId));

        try {        	
        	response = client.execute(request);
        	HttpEntity entity = response.getEntity();

        	return XMLToBussinessConversor.toAnswerQuestionResponseTO(entity);

        } catch (ServerException e) {
        	throw e;
        } catch(IOException e) {
        	throw new ServerException(ServerException.SERVER_OFFLINE_CODE, 
			e.getMessage());
        } catch (Exception e) {
        	throw e;
        }
	}
}
